/*
 * Author: 李波(Edwin Lee)
 * Date: 2024-08-31 04:06:42
 * FilePath: /mprpc/src/zookeeperutil.cc
 * LastEditTime: 2024-09-02 02:50:04
 * version: 1.0
 * Description: 
 */

#include "zookeeperutil.h"
#include "mprpcapplication.h"
#include "logger.h"
#include <semaphore.h>
#include <iostream>

// 全局的watcher观察者
void global_watcher(zhandle_t* zh,int type,int state,const char* path,void* watcherCtx)
{
    // 回调消息类型是和会话相关的消息类型
    if(type == ZOO_SESSION_EVENT)
    {
		if(state == ZOO_CONNECTED_STATE) // zkclient和zkserver连接成功
		{
			sem_t *sem = (sem_t*)zoo_get_context(zh);
            sem_post(sem);
        }
    }
}

ZkClient::ZkClient():zhandle_(nullptr)
{
}

ZkClient::~ZkClient()
{
    if(nullptr != zhandle_)
    {
        zookeeper_close(zhandle_);
    }
}

void ZkClient::start()
{
    std::string host = MprpcApplication::getInstance().getConfig().load("zookeeperip");
    std::string port = MprpcApplication::getInstance().getConfig().load("zookeeperport");
    std::string connstr = host+":"+port;
	LOG_DEBUG("ZkClient::start()");
	/*
	zookeeper_mt：多线程版本
	zookeeper的API客户端程序提供了三个线程
	API调用线程 
	网络I/O线程  pthread_create  poll
	watcher回调线程 pthread_create
	*/
    zhandle_ = zookeeper_init(connstr.c_str(), global_watcher,30000,nullptr,nullptr,0);
    if(nullptr == zhandle_)
    {
        LOG_FATAL("zookeeper_init error!");
        exit(EXIT_FAILURE);
    }
    sem_t sem;
    sem_init(&sem, 0, 0);
    zoo_set_context(zhandle_, &sem);

    sem_wait(&sem);
    std::cout << "zookeeper_init success!" << std::endl;
}

void ZkClient::create(const char *path, const char *data, int datalen, int state)
{
    char path_buffer[128];
    int bufferlen = sizeof(path_buffer);
    int flag;
	// 先判断path表示的znode节点是否存在，如果存在，就不再重复创建了
	flag = zoo_exists(zhandle_, path, 0, nullptr);
    // 表示path的znode节点不存在
	if (ZNONODE == flag) 
	{
		// 创建指定path的znode节点了
		flag = zoo_create(zhandle_, path, data, datalen,
			&ZOO_OPEN_ACL_UNSAFE, state, path_buffer, bufferlen);
		if (flag == ZOK)
		{
			LOG_INFO("znode create success... path: %s",path);
		}
		else
		{
			LOG_FATAL("znode create error... path: %s,flag:%d",path,flag);
			exit(EXIT_FAILURE);
		}
	}
}

// 根据指定的path，获取znode节点的值
std::string ZkClient::getData(const char *path)
{
    char buffer[64];
	int bufferlen = sizeof(buffer);
	int flag = zoo_get(zhandle_, path, 0, buffer, &bufferlen, nullptr);
	if (flag != ZOK)
	{
		LOG_FATAL( "get znode error... path: %s", path);
		return "";
	}
	else
	{
		return buffer;
	}
}
